﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml.Serialization;

namespace FCSChart.Graphical
{
    /// <summary>
    /// 门的基类
    /// </summary>
    public abstract class BaseGraphical : NotifyPropertyChanged, IDisposable
    {
        #region property
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; protected set; } = "Graphical";
        /// <summary>
        /// 简称
        /// </summary>
        public string ShortName { get; protected set; } = "G";
        /// <summary>
        /// 父容器
        /// </summary>
        public ChartWithGraphicals OwnerChart { get; internal set; }

        protected bool isCreateing = false;
        /// <summary>
        /// 是否正在创建
        /// </summary>
        public bool IsCreateing
        {
            get { return isCreateing; }
            internal set
            {
                isCreateing = value;
                OnPropertyChanged("IsCreateing");
                if (!value)
                {
                    GraphicalShape.Focus();
                    DrawingControl();
                    RefreshAreaSource(this.OwnerChart.XValueConverter, this.OwnerChart.YValueConverter);
                }
            }
        }
        #endregion
        /// <summary>
        /// 门内的区域
        /// </summary>
        public GraphicalArea[] Areas { get; protected set; }
        public BaseGraphical() { IsCreateing = true; InitName(); }
        public BaseGraphical(BaseGraphicalModel model) { InitName(); }
        /// <summary>
        /// 初始化名称
        /// </summary>
        protected abstract void InitName();
        #region 容器鼠标事件-用于门的创建
        /// <summary>
        /// 容器鼠标按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal abstract void PanelMouseDown(object sender, MouseButtonEventArgs e);
        /// <summary>
        /// 容器鼠标移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal abstract void PanelMouseMove(object sender, MouseEventArgs e);
        /// <summary>
        /// 容器鼠标抬起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal abstract void PanelMouseUp(object sender, MouseButtonEventArgs e);
        #endregion


        #region 门显示相关
        private ContextMenu contextMenu;
        /// <summary>
        /// 图形右键菜单
        /// </summary>
        public ContextMenu ContextMenu
        {
            get
            {
                if (OwnerChart != null && !OwnerChart.CanRemoveGraphical) return null;
                if (contextMenu == null)
                {
                    contextMenu = new ContextMenu();
                    var menuitem = new MenuItem() { Header = "删除" };
                    menuitem.Click += (sender, e) => this.Dispose();
                    contextMenu.Items.Add(menuitem);
                }
                return contextMenu;
            }
            set { contextMenu = value; OnPropertyChanged("ContextMenu"); }
        }
        private Brush fill = Helper.GetNewSolidColorBrush(0x1);
        /// <summary>
        /// 填充色
        /// </summary>
        public Brush Fill
        {
            get { return fill; }
            set { fill = value; OnPropertyChanged("Fill"); }
        }
        private Brush stroke = Brushes.Black;
        /// <summary>
        /// 边框色
        /// </summary>
        public Brush Stroke
        {
            get { return stroke; }
            set { stroke = value; OnPropertyChanged("Stroke"); }
        }
        private double strokeThickness = 1;
        /// <summary>
        /// 边框宽度
        /// </summary>
        public double StrokeThickness
        {
            get { return strokeThickness; }
            set { strokeThickness = value; OnPropertyChanged("StrokeThickness"); }
        }
        private Shape graphicalShape;
        /// <summary>
        /// 门的显示图形
        /// </summary>
        protected Shape GraphicalShape
        {
            get { return graphicalShape; }
            set
            {
                graphicalShape = value;
                if (value != null)
                {
                    OwnerChart.ViewPanel.Children.Add(value);
                }
            }
        }
        /// <summary>
        /// 绘制门
        /// </summary>
        internal abstract void Drawing();

        #region 门事件--移动，选中
        /// <summary>
        /// 移动门
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        internal abstract void Move(double x, double y);
        protected Point GraphicalMoveStartPoint { get; set; }
        protected virtual void Graphical_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.OwnerChart.CanChangeGraphical)
            {
                GraphicalMoveStartPoint = e.GetPosition(OwnerChart.ViewPanel);
                GraphicalShape.Focus();
                e.Handled = true;
            }
        }
        protected virtual void Graphical_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.OwnerChart.CanChangeGraphical && e.LeftButton == MouseButtonState.Pressed)
            {
                if (GraphicalMoveStartPoint != default)
                {
                    var point = e.GetPosition(OwnerChart.ViewPanel);
                    var x = point.X - GraphicalMoveStartPoint.X;
                    var y = point.Y - GraphicalMoveStartPoint.Y;
                    GraphicalMoveStartPoint = point;
                    Move(x, y);
                    e.Handled = true;
                }
            }
            else GraphicalMoveStartPoint = default;
        }
        #endregion
        #endregion

        #region 门控制
        private ObservableCollection<Shape> controlShapes;
        /// <summary>
        /// 控制图形的点位图形
        /// </summary>
        protected ObservableCollection<Shape> ControlShapes
        {
            get
            {
                if (controlShapes == null)
                {
                    controlShapes = new ObservableCollection<Shape>();
                    controlShapes.CollectionChanged += (sender, e) =>
                    {
                        switch (e.Action)
                        {
                            case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                                foreach (var item in e.NewItems)
                                {
                                    if (item is Shape shape)
                                    {
                                        shape.Fill = Brushes.Black;
                                        shape.SetBinding(UIElement.VisibilityProperty, new Binding("IsFocused") { Source = this.GraphicalShape, Converter = Converters.BoolToVisibilityConverter.Converter });
                                        shape.MouseLeftButtonDown += Shape_MouseLeftButtonDown;
                                        OwnerChart.ViewPanel.Children.Add(shape);
                                    }
                                }
                                break;
                            case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                                foreach (var item in e.OldItems)
                                {
                                    if (item is Shape shape)
                                    {
                                        shape.MouseLeftButtonDown -= Shape_MouseLeftButtonDown;
                                        OwnerChart.ViewPanel.Children.Remove(shape);
                                    }
                                }
                                break;
                            case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                                break;
                            case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                                break;
                            case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                                break;
                            default:
                                break;
                        }
                    };
                }
                return controlShapes;
            }
        }

        internal Shape ControledShape { get; set; }
        /// <summary>
        /// 门控制点按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Shape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            GraphicalMoveStartPoint = default;
            ControledShape = sender as Shape;
            e.Handled = true;
        }
        /// <summary>
        /// 门控制点移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Shape_MouseMove(object sender, MouseEventArgs e)
        {
            e.Handled = true;
        }
        /// <summary>
        /// 门控制按钮鼠标抬起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Shape_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (this.OwnerChart.CanChangeGraphical) RefreshAreaSource(this.OwnerChart.XValueConverter, this.OwnerChart.YValueConverter);
        }
        /// <summary>
        /// 绘制控制按钮
        /// </summary>
        protected abstract void DrawingControl();

        #endregion
        /// <summary>
        /// 是否正在刷新门内数据
        /// </summary>
        public bool IsRefreshingAreaSource { get; protected set; }
        /// <summary>
        /// 门内数据判断计算控制
        /// </summary>
        protected System.Threading.CancellationTokenSource CancelTokenSource { get; set; }
        /// <summary>
        /// 更新门划分的区域内数据
        /// </summary>
        /// <param name="xValueConverter"></param>
        /// <param name="yValueConverter"></param>
        internal abstract void RefreshAreaSource(Func<object, double> xValueConverter, Func<object, double> yValueConverter);

        /// <summary>
        /// 创建新的门数据模型
        /// </summary>
        public abstract BaseGraphicalModel GetGraphicalMode();
        /// <summary>
        /// 清理资源--删除图形时可调用
        /// </summary>
        public virtual void Dispose()
        {
            if (OwnerChart != null && OwnerChart.ViewPanel != null)
            {
                if (GraphicalShape != null && OwnerChart.ViewPanel.Children.Contains(GraphicalShape))
                    OwnerChart.ViewPanel.Children.Remove(GraphicalShape);
                if (ControlShapes != null && ControlShapes.Count > 0)
                {
                    foreach (var shape in ControlShapes)
                    {
                        if (OwnerChart.ViewPanel.Children.Contains(shape))
                            OwnerChart.ViewPanel.Children.Remove(shape);
                    }
                }
                if (OwnerChart.Graphicals.Contains(this)) OwnerChart.Graphicals.Remove(this);
            }

            if (Areas != null)
            {
                if (this.OwnerChart != null) this.OwnerChart.RemoveGraphicalArea(Areas);
                Areas = null;
            }
        }

        /// <summary>
        /// 门模型集合转门集合
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public static List<BaseGraphical> GraphicalModelsToGraphical(params BaseGraphicalModel[] models)
        {
            List<BaseGraphical> graphicals = new List<BaseGraphical>();
            if (models != null && models.Length > 0)
                foreach (var model in models)
                {
                    if (model is SegmentXGraphicalModel sx) graphicals.Add(new SegmentXGraphical(sx));
                    else if (model is SegmentYGraphicalModel sy) graphicals.Add(new SegmentYGraphical(sy));
                    else if (model is RectangleGraphicalModel r) graphicals.Add(new RectangleGraphical(r));
                    else if (model is PolygonGraphicalModel p) graphicals.Add(new PolygonGraphical(p));
                    else if (model is QuadrantGraphicalModel q) graphicals.Add(new QuadrantGraphical(q));
                    else if (model is LineHorizontalGraphicalModel lh) graphicals.Add(new LineHorizontalGraphical(lh));
                    else if (model is LineVerticalGraphicalModel lv) graphicals.Add(new LineVerticalGraphical(lv));
                }
            return graphicals;
        }

        public static BaseGraphical CreateFromGraphicalName(string graphicalName)
        {
            switch (graphicalName)
            {
                case "LineHorizontal":
                    return new LineHorizontalGraphical();
                case "LineVertical":
                    return new LineVerticalGraphical();
                case "Polygon":
                    return new PolygonGraphical();
                case "Quadrant":
                    return new QuadrantGraphical();
                case "Rectangle":
                    return new RectangleGraphical();
                case "SegmentX":
                    return new SegmentXGraphical();
                case "SegmentY":
                    return new SegmentYGraphical();
                default:
                    return null;
            }
        }
    }


    /// <summary>
    /// 门划分后的区域
    /// </summary>
    public class GraphicalArea : NotifyPropertyChanged
    {
        internal FrameworkElement DisplayElement { get; set; }

        private string name;
        /// <summary>
        /// 名称
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }

        private Point center;
        /// <summary>
        /// 区域中心点-图表中的位置
        /// </summary>
        public Point Center
        {
            get { return center; }
            set { center = value; OnPropertyChanged("Center"); }
        }

        private IList<int> insideIndexs;
        /// <summary>
        /// 区域内数据的索引集合
        /// </summary>
        public IList<int> InsideIndexs
        {
            get { return insideIndexs; }
            set
            {
                insideIndexs = value;
                OnPropertyChanged("InsideIndexs");
            }
        }

        private Color displayColor = Helper.GetNewColor();
        /// <summary>
        /// 图中显示的颜色
        /// </summary>
        public Color DisplayColor
        {
            get { return displayColor; }
            set { displayColor = value; OnPropertyChanged("DisplayColor"); }
        }
        /// <summary>
        /// 区域所属的门
        /// </summary>
        public BaseGraphical OwnerGraphical { get; internal set; }
    }


    [XmlInclude(typeof(LineHorizontalGraphicalModel))]
    [XmlInclude(typeof(LineVerticalGraphicalModel))]
    [XmlInclude(typeof(PolygonGraphicalModel))]
    [XmlInclude(typeof(QuadrantGraphicalModel))]
    [XmlInclude(typeof(RectangleGraphicalModel))]
    [XmlInclude(typeof(SegmentXGraphicalModel))]
    [XmlInclude(typeof(SegmentYGraphicalModel))]
    public abstract class BaseGraphicalModel
    {
        public string[] AreaNames { get; set; }

        [XmlIgnore]
        internal Color[] AreaColors { get; set; }

        public string[] Colors
        {
            get
            {
                return AreaColors.Select(p => string.Concat(p.A.ToString("X2"), p.R.ToString("X2"), p.G.ToString("X2"), p.B.ToString("X2"))).ToArray();
            }
            set
            {
                AreaColors = value.Select(p => new Color() { A = Convert.ToByte(p.Substring(0, 2), 16), R = Convert.ToByte(p.Substring(2, 2), 16), G = Convert.ToByte(p.Substring(4, 2), 16), B = Convert.ToByte(p.Substring(6, 2), 16) }).ToArray();
            }
        }
    }
}
